package main.bio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @Author: XJL
 * @Description:
 * @Date: Create in 22:18 2022-04-19
 * @Modified By:
 **/
public class NioSocketServer extends Thread {

    ServerSocketChannel serverSocketChannel = null;
    Selector selector = null;
    SelectionKey selectionKey = null;

    public void initServer() throws IOException {
        selector = Selector.open();
        serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞模式,默认serverSocketChannel是采用了阻塞模式
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));
        selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    @Override
    public void run() {

        while (true) {
            try {
                //默认这里会堵塞
                int selectKey = selector.select();
                if (selectKey > 0) {
                    //获取到所有的处于就绪状态的channel，selectionKey中包含了channel的信息
                    Set<SelectionKey> keySet = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = keySet.iterator();
                    //对selectionkey进行遍历
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = iterator.next();
                        //需要清空，防止下次重复处理
                        iterator.remove();
                        //就绪事件，处理连接
                        if (selectionKey.isAcceptable()) {
                            accept(selectionKey);
                        }
                        //读事件，处理数据读取
                        if (selectionKey.isReadable()) {
                            read(selectionKey);
                        }
                        //写事件，处理写数据
                        if (selectionKey.isWritable()) {

                        }
                   }
                }

            } catch (Exception e) {
                e.printStackTrace();

                try {
                    serverSocketChannel.close();
                    selectionKey.cancel();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private void read(SelectionKey selectionKey) {
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(100);

        try {
            int len = channel.read(byteBuffer);

            while (len > 0) {
                byteBuffer.flip();
                byte[] byteArray = new byte[byteBuffer.limit()];
                byteBuffer.get(byteArray);
                System.out.println("NioSocketServer receive from client:" + new String(byteArray,0,len));
                selectionKey.interestOps(SelectionKey.OP_READ);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void accept(SelectionKey selectionKey) {
        try {
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            System.out.println("conn is acceptable");

            socketChannel.configureBlocking(false);
            //将当前的channel交给selector对象监管，并且有selector对象管理它的读事件
            socketChannel.register(selector, SelectionKey.OP_READ);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws IOException {
        NioSocketServer socketServer = new NioSocketServer();
        socketServer.initServer();
        socketServer.start();
    }
}
